Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat #73 post,notice, receipt 파일 업로드 수정 #73

Merged
merged 42 commits into from
Nov 24, 2024

Conversation

hyxklee
Copy link
Member

@hyxklee hyxklee commented Nov 19, 2024

PR 내용

  • 기존 MultipartFile로 파일을 입력 받아 서버에서 S3로 파일 업로드를 하던 것을 presigned url을 이용해 프론트와 비동기적으로 하도록 수정했습니다
  • 해당작업은 파일이 들어가는 Post, Notice, Receipt 3개의 도메인에 대해 작업을 했습니다.

PR 세부사항

  • 프론트는 사용자가 파일을 첨부하면 presigned url을 서버로 요청합니다. 서버는 바로 url을 반환하고, 파일이 첨부된 게시글, 공지 등이 저장이 되면 s3 객체 url을 서버로 보내고, put 요청으로 이미지를 업로드 합니다
  • 따라서 서버가 파일을 업로드 할 때 발생하는 네트워크 지연과, 속도 지연을 감소할 수 있습니다.
  • 파일 업로드는 필수가 아니기 때문에 files를 [], 즉 빈 리스트로 보낼 수 있습니다. 또는 생략할 수 있습니다. 하지만 null이 오게되면 내부에서 nullPointException이 발생하기 때문에 유효성 검증을 했습니다.

관련 스크린샷

image image image

주의사항

  • 최대한 모든 케이스에 대한 dto 유효성 검사를 추가했고 확인해봤는데 이상은 찾지 못했으나, 파일이 없는 경우, null인 경우, 빈 리스트인 경우, fileName이 없는 경우, fileUrl이 없는 경우 등 케이스가 너무 많아서 체크가 안된 부분이 있을 수 있습니다. 관련 부분 봐주시면 감사하겠습니다
  • 작업 중에 jwt filter에 오류가 있어 예외를 던지는 방식으로 수정했습니다. 자잘한 오류가 발견되어 차후에 작업할 계획입니다.
  • 스웨거에서도 api 응답 속도를 볼 수 있는 설정을 추가했습니다

체크 리스트

  • 리뷰어 설정
  • Assignee 설정
  • Label 설정
  • 제목 양식 맞췄나요? (ex. #0 Feat: 기능 추가)
  • 변경 사항에 대한 테스트

@hyxklee hyxklee self-assigned this Nov 19, 2024
@hyxklee hyxklee changed the title Feat #72 post,notice, receipt 파일 업로드 수정 Feat #73 post,notice, receipt 파일 업로드 수정 Nov 19, 2024
Copy link
Collaborator

@jj0526 jj0526 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨어요!!

fileRepository.delete(file);
}

public void delete(List<File> files) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메소드 이름을 deleteAll로 하는게 나아보여용

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

단일 파일 삭제랑 구분하기 위해서 deleteAll이 더 직관적인거 같습니다 !

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메서드 명에 대한 추상화를 위해 메서드 오버로딩을 사용해 같은 메서드 명으로 사용했습니다!
메서드 명은 같지만 파라미터의 타입이 다르기 때문에 구분이 가능하고, 외부에서는 캡슐화를 통해 메서드의 자세한 로직은 숨기고, 다형성을 구현해 확장성과 유연성을 조금이나마 확보할 수 있다고 생각하는데 이런 관점에서는 어떻게 생각하시나요??
구분하는게 나을 것 같다면 수정 하겠습니다!

@Service
@RequiredArgsConstructor
public class FileUpdateService {

public void update(File file, FileUpdateRequest dto) {
file.update(dto.fileName(), dto.fileUrl());
}

public void updateFiles(List<File> fileList, List<FileUpdateRequest> dto) {
for (File file : fileList) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시라도 둘중 하나라도 비어있을 수 있으니 exception을 추가하면 좋아보여요!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 해당 부분에 서비스단에서 비어있을 경우의 예외처리를 던져주는 방식이 좋아보입니당

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

파일의 경우 업로드가 될 수도 있고 안될 수도 있기 때문에 비어있는 경우에 예외를 날리기 보다는 저장된 파일이 있는 지 usecase에서 체크해서 해당 메서드를 호출하고, dto가 null이 아닌 경우에만 로직이 돌아가게 수정 하겠습니다.
그리고 입력된 fileId가 올바른지 아닌지 검증하는 로직을 추가하겠습니다

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵!

return fileGetService.findAllByPost(postId);
}

private Post validateOwner(Long postId, Long userId) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

void 형이 더 좋을거같아요

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 Notice의 validateOwner와 마찬가지 입니당

return fileGetService.findAllByNotice(noticeId);
}

private Notice validateOwner(Long noticeId, Long userId) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

검증만을 위해서면 void형을 사용해서 더 명확하게 할수있을거같아여

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

모든 메서드에
Notice notice = noticeFindService.find(noticeId); 가 포함되고 있어서 해당 코드 반복을 줄이고자 이 메서드에서 find에서 return 하는 것으로 구현 했어요!

}

@Override
public void delete(Long noticeId, Long userId) throws UserNotMatchException {
@Transactional
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 여기에 @transactional(rollbackFor = UserNotMatchException.class)로 바뀌는게 더 나을까요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UserNotMatchException이 RuntimeException을 상속하는 BusinessLogicException을 상속하기 때문에 예외 발생시 롤백이 돼서 추가하지 않아도 될 것 같아요!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아하 그렇군요

Copy link
Member

@huncozyboy huncozyboy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생많으셨습니다 !! 👏

@Service
@RequiredArgsConstructor
public class FileUpdateService {

public void update(File file, FileUpdateRequest dto) {
file.update(dto.fileName(), dto.fileUrl());
}

public void updateFiles(List<File> fileList, List<FileUpdateRequest> dto) {
for (File file : fileList) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 해당 부분에 서비스단에서 비어있을 경우의 예외처리를 던져주는 방식이 좋아보입니당

Comment on lines 23 to 33
@Mapping(target = "id", ignore = true)
@Mapping(target = "post", source = "post")
File toFile(String fileName, String fileUrl, Post post);

@Mapping(target = "id", ignore = true)
@Mapping(target = "notice", source = "notice")
File toFile(String fileName, String fileUrl, Notice notice);

@Mapping(target = "id", ignore = true)
@Mapping(target = "receipt", source = "receipt")
File toFile(String fileName, String fileUrl, Receipt receipt);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toFile의 변수명으로 post, notice, receipt보다는
linkedPost, linkedNotice, linkedReceipt로 더 의미를 명확하게 해주는건 어떨까요

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toFileWithPost 이런 식은 어떨까용?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

굳굳 좋습니다

fileRepository.delete(file);
}

public void delete(List<File> files) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

단일 파일 삭제랑 구분하기 위해서 deleteAll이 더 직관적인거 같습니다 !

Copy link
Collaborator

@jj0526 jj0526 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨습니다 !

@hyxklee hyxklee merged commit 9e56411 into develop Nov 24, 2024
2 checks passed
@hyxklee hyxklee deleted the feat/#70/post,notice-파일-업로드-수정 branch November 24, 2024 11:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants